// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.util.List;
#pragma once

#include <string>
#include <list>

#include "SQLSelectItem.h"

#include "../SQLExpr.h"
#include "../SQLObjectImpl.h"
#include "../SQLOrderingSpecification.h"
#include "../SQLReplaceable.h"

class SQLASTVisitor;
class SQLSelectOrderByItem_NullsOrderType
{
public:
  static SQLSelectOrderByItem_NullsOrderType NullsFirst;
  static SQLSelectOrderByItem_NullsOrderType NullsLast;
  string_ptr name;
  uint64_t index;
  SQLSelectOrderByItem_NullsOrderType() {}
  SQLSelectOrderByItem_NullsOrderType(string_ptr name, uint64_t index);
  SQLSelectOrderByItem_NullsOrderType(SQLSelectOrderByItem_NullsOrderType *nullsOrderType);
  string_ptr toFormalString();
};

class SQLSelectOrderByItem : virtual public SQLObjectImpl, virtual public SQLReplaceable
{
public:
  SQLExpr_ptr expr;
  string_ptr collate;
  SQLOrderingSpecification_ptr type;
  SQLSelectOrderByItem_NullsOrderType_ptr nullsOrderType;

  SQLSelectItem_ptr resolvedSelectItem;

  SQLSelectOrderByItem();

  SQLSelectOrderByItem(SQLExpr_ptr expr);

  SQLSelectOrderByItem(SQLExpr_ptr expr, SQLOrderingSpecification_ptr type);
  SHAREDOBJECT(SQLSelectOrderByItem);

  SQLExpr_ptr getExpr();

  void setExpr(SQLExpr_ptr expr);
  void setExpr(SQLObject_ptr expr);

  string_ptr getCollate();

  void setCollate(string_ptr collate);

  SQLOrderingSpecification_ptr getType();

  void setType(SQLOrderingSpecification_ptr type);

  SQLSelectOrderByItem_NullsOrderType_ptr getNullsOrderType();

  void setNullsOrderType(SQLSelectOrderByItem_NullsOrderType_ptr nullsOrderType);

  void accept0(SQLASTVisitor_ptr v);

  // int hashCode() {
  //     int prime = 31;
  //     int result = 1;
  //     result = prime * result + ((collate.empty()) ? 0 : collate.hashCode());
  //     result = prime * result + ((expr == NULL) ? 0 : expr->hashCode());
  //     result = prime * result + ((type == NULL) ? 0 : type->hashCode());
  //     return result;
  // }

  // BOOL_ptr equals(Object obj) {
  //     if (this == obj) {
  //         return BOOL::TRUE;
  //     }
  //     if (obj == NULL) {
  //         return BOOL::FALSE;
  //     }
  //     if (getClass() != obj.getClass()) {
  //         return BOOL::FALSE;
  //     }
  //     SQLSelectOrderByItem other = (SQLSelectOrderByItem) obj;
  //     if (collate == NULL) {
  //         if (other.collate != NULL) {
  //             return BOOL::FALSE;
  //         }
  //     } else if (!collate.equals(other.collate)) {
  //         return BOOL::FALSE;
  //     }
  //     if (expr == NULL) {
  //         if (other.expr != NULL) {
  //             return BOOL::FALSE;
  //         }
  //     } else if (!expr.equals(other.expr)) {
  //         return BOOL::FALSE;
  //     }
  //     if (type != other.type) {
  //         return BOOL::FALSE;
  //     }
  //     return BOOL::TRUE;
  // }

  // BOOL_ptr replace(SQLExpr_ptr expr, SQLExpr_ptr target) {
  //     if (this->expr == expr) {
  //         if (target instanceof SQLIntegerExpr && parent instanceof SQLOrderBy) {
  //             ((SQLOrderBy) parent).getItems().remove(this);
  //         }
  //         this->setExpr(target);
  //         return BOOL::TRUE;
  //     }
  //     return BOOL::FALSE;
  // }

  virtual SQLObject_ptr clone();

  SQLSelectItem_ptr getResolvedSelectItem();

  void setResolvedSelectItem(SQLSelectItem_ptr resolvedSelectItem);

  // BOOL_ptr isClusterBy() {
  //     if (parent instanceof SQLCreateTableStatement) {
  //         std::list<SQLSelectOrderByItem> clusteredBy = ((SQLCreateTableStatement) parent).getClusteredBy();
  //         return clusteredBy.indexOf(this) != -1;
  //     }

  //     if (parent instanceof SQLSelectQueryBlock) {
  //         std::list<SQLSelectOrderByItem> clusterBy = ((SQLSelectQueryBlock) parent).getClusterByDirect();
  //         return clusterBy != NULL && clusterBy.indexOf(this) != -1;
  //     }

  //     return BOOL::FALSE;
  // }

  // BOOL_ptr isSortBy() {
  //     if (parent instanceof SQLCreateTableStatement) {
  //         std::list<SQLSelectOrderByItem> sortedBy = ((SQLCreateTableStatement) parent).getSortedBy();
  //         return sortedBy.indexOf(this) != -1;
  //     }

  //     if (parent instanceof SQLSelectQueryBlock) {
  //         std::list<SQLSelectOrderByItem> sortedBy = ((SQLSelectQueryBlock) parent).getSortByDirect();
  //         return sortedBy != NULL && sortedBy.indexOf(this) != -1;
  //     }

  //     return BOOL::FALSE;
  // }

  // BOOL_ptr isDistributeBy() {
  //     if (parent instanceof SQLSelectQueryBlock) {
  //         std::list<SQLSelectOrderByItem> distributeBy = ((SQLSelectQueryBlock) parent).getDistributeBy();
  //         return distributeBy.indexOf(this) != -1;
  //     }

  //     return BOOL::FALSE;
  // }
};
